#include "pbcpu.h"
#include "../utils/utils.h"

#include <stdio.h>
#include <float.h>
#include <math.h>


//
// egyszeru szamolosdi
//

#define MAX         1


template<typename TYPE>
static void func(const char *msg, IResultWriter *results)
{   
    double start = os_GetTime();

    volatile TYPE sum = 0;

    for (int i=0; i<MAX; i++)
    {
        for (TYPE j=0; j<10000; j++)
        {
            for (TYPE k=0; k<1000; k++)
            {            
                sum += k * j + 17 * j / (k + ((k || j) ? (k + j * 3) : 1));
            }               
        }
    }

    double end = os_GetTime();

    results->WriteNode(ft("simple_%s", msg), (float)(end-start));
}

static void Cpu(const char *msg, IResultWriter *results)
{    
    func<int16_t>("int16_t", results);
    func<uint16_t>("uint16_t", results);
    func<int32_t>("int32_t", results);
    func<int32_t>("uint32_t", results);
    func<int64_t>("int64", results);
    func<uint64_t>("uint64", results);    
}

static void Fpu(const char *msg, IResultWriter *results)
{    
    char buff[128];
    sprintf(buff, "float%s", msg);
    func<float>(buff, results);
    sprintf(buff, "double%s", msg);
    func<double>(buff, results);
}


// 
// sakktabla: vegig lehet-e lepkedni a loval adott pontbol kiindulva, minden mezot erintve
//
// (1999-bol :))

unsigned int tabla[8][8];

static int dx[] = {  1,  2,  2,  1, -1, -2, -2, -1};
static int dy[] = { -2, -1,  1,  2,  2,  1, -1, -2};


static void Probal(int x, int y, int lepes, int *eredmeny) 
{

    unsigned int ujx, ujy;
    int q=0, i=0;

    do
    {
        ujx = x + dx[i];
        ujy = y + dy[i];

        if (ujx < 8 && ujy < 8 && tabla[ujy][ujx] == 0) 
        {
            tabla[ujy][ujx] = lepes;            

            if (lepes < 64)
            {
                Probal(ujx, ujy, lepes+1, &q);
                if (q == 0)
                    tabla[ujy][ujx] = 0;
            }
            else
                q = 1;
        }
        i++;
    } while (i < 8 && q == 0);

    *eredmeny = q;
}


static int Lehetseges_e_XY_bol_bejarni(int x, int y, IResultWriter *results)
{
    double start = os_GetTime();

    int sikerult;

    memset(tabla, 0, sizeof(tabla));
    tabla[y][x] = 1;
    Probal(x, y, 2, &sikerult);

    double end = os_GetTime();

    results->WriteNode("knight", (float)(end-start));

    return sikerult;
}
  
//
// FFT
//

static void Fill(double *d, int32_t size)
{
   // The frequency is 5
   double b = (M_PI * 2) * 5/size;
   for (int x = 0; x < size; ++x)
      d[x] =  cos(x*b);
}

void fourier(int32_t n, int16_t isgn, double* a);   // gpfft.cpp


static void FftTest(int32_t size, IResultWriter *results)
{
    double *data = (double*)malloc(size * sizeof(double));

    if (!data)
        return;
        
    Fill(data, size);

    double start = os_GetTime();
    fourier(size, -1, data);
    double end = os_GetTime();                           

    free(data);

    results->WriteNode(ft("fft%d", size), (float)(end-start));
}

//
// fibonacci
//

static uint32_t fib(uint32_t n) 
{
    return n < 2 ? 1 : (fib(n-2) + fib(n-1));
}

static uint32_t Fibonacci(uint32_t n, IResultWriter *results)
{
    double start = os_GetTime();
    uint32_t result = fib(n);
    double end = os_GetTime();

    results->WriteNode(ft("fibonacci%u", result), (float)(end-start));
    return result;
}


void CCpuBenchmark::Run(IResultWriter *results, const CCmdlineArgs *args)
{   
    Lehetseges_e_XY_bol_bejarni(0, 7, results);
 
    FftTest(1<<19, results);
    
    Fibonacci(38, results); 

    Cpu("", results);

    Fpu("_d", results);

/*
    _controlfp(_PC_24, _MCW_PC);
    Fpu("_PC_24", results);
    
    _controlfp(_PC_53, _MCW_PC);
    Fpu("_PC_53", results);

    _controlfp(_PC_64, _MCW_PC);
    Fpu("_PC_64", results);
*/
}
